package com.google.code.jcooky.rpc.compiler.java;

import static com.google.code.jcooky.rpc.compiler.StringUtils.copyOfString;
import static com.google.code.jcooky.rpc.compiler.StringUtils.read;
import static com.google.code.jcooky.rpc.compiler.StringUtils.toJavaType;

import java.io.IOException;
import java.util.List;
import java.util.Map;

import com.google.code.jcooky.rpc.compiler.Processor;

public class JavaServiceProcessor extends Processor {
	private String service_layout, service_client_body_layout, service_client_return_body_layout, service_iface_body_layout, transport_add_arguments_layout;
	
	public JavaServiceProcessor() throws IOException  {
		super();
		
		service_layout = read("service.layout");
		service_client_body_layout = read("service_client_body.layout");
		service_iface_body_layout = read("service_iface_body.layout");
		service_client_return_body_layout = read("service_client_body_return.layout");
		transport_add_arguments_layout = read("transport_add_arguments.layout");
	}

	public void process(Map<String, Object> attr) throws ProcessException {
		String strbuf = "";
		
		String serviceName = (String)attr.get("service_name");
		List<Map<String, Object>> methods = (List<Map<String, Object>>)attr.get("methods");
		strbuf = copyOfString(service_layout);
		strbuf = strbuf.replace("%namespace%", getNamespace());
		strbuf = strbuf.replace("%service_name%", serviceName);
		strbuf = strbuf.replace("%iface_body.layout%", getServiceIfaceBody(methods));
		strbuf = strbuf.replace("%client_body.layout%", getServiceClientBody(methods));
		
		write(strbuf, serviceName);
	}
	
	private String getServiceIfaceBody(List<Map<String, Object>> attr) {
		StringBuffer strbuf = new StringBuffer(256);
		for(Map<String, Object> m : attr) {
			String src = copyOfString(service_iface_body_layout);
			src = src.replace("%type%", toJavaType((String)m.get("method_type"), getNamespace()));
			src = src.replace("%method%", (String)m.get("method_name"));
			src = src.replace("%arguments.layout%", getArgs((List<Map<String, Object>>)m.get("method_arguments")));
			strbuf.append(src).append("\n");
		}
		return strbuf.toString();
	}
	
	private String getArgs(List<Map<String, Object>> attr) {
		StringBuffer strbuf = new StringBuffer(256);
		for(Map<String, Object> m : attr) {
			String src = copyOfString(arguments_layout);
			src = src.replace("%arg_type%", toJavaType((String)m.get("argument_type"), getNamespace()));
			src = src.replace("%arg_name%", (String)m.get("argument_name"));
			strbuf.append(src).append(", ");
		}
		return strbuf.length() == 0 ? "" : strbuf.substring(0, strbuf.length()-2);
	}
	
	private String getServiceClientBody(List<Map<String, Object>> attr) {
		StringBuffer strbuf = new StringBuffer(256);
		for(Map<String, Object> m : attr) {
			List<Map<String, Object>> args = (List<Map<String, Object>>)m.get("method_arguments");
			String methodType = toJavaType((String)m.get("method_type"), getNamespace());
			String src = copyOfString(service_client_body_layout);
			src = src.replaceAll("%service_client_body_return.layout%", methodType.equals("void") ? "" : getReturn(methodType));
			src = src.replaceAll("%method_type%", methodType);
			src = src.replaceAll("%method_name%", (String)m.get("method_name"));
			src = src.replace("%arguments.layout%", getArgs(args));
			src = src.replace("%transport_add_arguments.layout%", getTransportAddArgs(args));
			strbuf.append(src).append("\n");
		}
		return strbuf.toString();
	}
	
	private String getReturn(String methodType) {
		String src = copyOfString(service_client_return_body_layout);
		src = src.replaceAll("%type%", methodType);
		return src;
	}
	
	private String getTransportAddArgs(List<Map<String, Object>> attr) {
		StringBuffer strbuf = new StringBuffer(256);
		for(Map<String, Object> m : attr) {
			String src = copyOfString(transport_add_arguments_layout);
			src = src.replaceAll("%arg_type%", toJavaType((String)m.get("argument_type"), getNamespace()));
			src = src.replaceAll("%arg_name%", (String)m.get("argument_name"));
			strbuf.append(src).append("\n");
		}
		return strbuf.toString();
	}
}


//{methods=[{method_name=hello2,
//method_arguments=[{argument_type=string, argument_name=a},
//{argument_type=string, argument_name=b}], method_type=string},
//{method_name=hel
//lo, method_arguments=[], method_type=test_struct}, {method_name=testHello,
//method_arguments=[{argument_type=int, argument_name=id}], method_type=void}],
//sevice_name=test_service}